/**
 * @file Perseus.cpp
 * @author ultralyj (1951578@tongji.edu.cn)
 * @brief 项目主体文件，运行可得sum,max,sort三种算法的
 *          原始,omp,avx+omp,cuda,4种并行处理方案的性能对比
 * @version 0.1
 * @date 2021-12-15
 * 
 * @copyright Copyright (c) 2021
 * 
 */

#include "perseus.h"

#define NN 100000000


void qrs_performance_test_sum();
void qrs_performance_test_max();
void qrs_performance_test_qsort();

void client_func(int32_t func);

/**
 * @brief main函数
 * 
 * @param arc 
 * @param arg 
 * @return int 
 */
int main(int arc, char* arg[])
{
    // qrs_performance_test_sum();
    // qrs_performance_test_max
    // qrs_performance_test_qsort();
    return 0;
    
}

void qrs_performance_test_sum()
{
    /* 建立TCP/IP服务器 */
    prs_tcp_server server;
    server.serverIp = "127.0.0.1";
    server.serverPort = 8081;
    /* 开始监听客户端 */
    server.begin();

    /* 建立随机变量 */
    printf("[%lf]begin to generate random array\n", fmod(omp_get_wtime(),10.0f));
    prs_rands  r;
    r.bypass(NN);
    printf("[%lf]array generated successfully\n", fmod(omp_get_wtime(), 10.0f));

    /* 时间记录相关变量 */
    double timeBegin = 0, timeCurrent = 0, timeRef[4] = {0};

    /* 测试1：遍历求和 */
    printf("[%lf]test1:get max by origin way\n", fmod(omp_get_wtime(), 10.0f));
    timeBegin = omp_get_wtime();
    double_t sum_origin = prs_sum(r.seq, r.n);
    timeCurrent = omp_get_wtime();
    timeRef[0] = timeCurrent - timeBegin;

    /* 测试2：OMP加速求和 */
    printf("[%lf]test2:speed up with openmp\n", fmod(omp_get_wtime(), 10.0f));
    timeBegin = omp_get_wtime();
    double_t sum_omp = prs_sum_omp(r.seq, r.n);
    timeCurrent = omp_get_wtime();
    timeRef[1] = timeCurrent - timeBegin;

    /* 测试3：OMP+AVX加速求和 */
    printf("[%lf]test3:speed up with OMP and AVX.ISA\n", fmod(omp_get_wtime(), 10.0f));
    timeBegin = omp_get_wtime();
    double_t sum_avx = prs_sum_omp_avx(r.seq, r.n);
    timeCurrent = omp_get_wtime();
    timeRef[2] = timeCurrent - timeBegin;

    /* 测试4：TCP/IP加速 */
    printf("[%lf]test4:speed up with TCP/IP\n", fmod(omp_get_wtime(), 10.0f));
    double_t sum_from_s = 0.0f, sum_from_c = 0.0f;
    timeBegin = omp_get_wtime();
#pragma omp parallel
    {
#pragma omp sections 
        {
#pragma omp section
            {
                server.tx(&(r.seq[NN / 2]), NN / 2);
            }
#pragma omp section
            {
                sum_from_s = prs_sum(r.seq, NN / 2);
            }
        }

    }
    //printf("finish max=%f\n", max_from_s);
    server.rx(&sum_from_c, 1);
    //printf("get client max=%f\n", max_from_c);
    double_t sum_tcp = prs_sum_merge(sum_from_s, sum_from_c);
    timeCurrent = omp_get_wtime();
    timeRef[3] = timeCurrent - timeBegin;
    
    /* 输出报告 */
    printf("\n_______________SUM___SUMMARY__________________\n");
    printf("|method\t|        value\t\t| time\t| ACR\t|\n");
    printf("----------------------------------------------\n");
    printf("|orign\t|  %.4f\t|%.4lf\t|%.3lf\t|\n", sum_origin, timeRef[0], timeRef[0] / timeRef[0]);
    printf("| omp\t|  %.4f\t|%.4lf\t|%.3lf\t|\n", sum_omp, timeRef[1], timeRef[0] / timeRef[1]);
    printf("| avx\t|  %.4f\t|%.4lf\t|%.3lf\t|\n", sum_avx, timeRef[2], timeRef[0] / timeRef[2]);
    printf("|TCPIP\t|  %.4f\t|%.4lf\t|%.3lf\t|\n", sum_tcp, timeRef[3], timeRef[0] / timeRef[3]);
}

void qrs_performance_test_max()
{
    /* 建立TCP/IP服务器 */
    prs_tcp_server server;
    server.serverIp = "127.0.0.1";
    server.serverPort = 8081;
    /* 开始监听客户端 */
    server.begin();

    /* 建立随机变量 */
    printf("[%lf]begin to generate random array\n", fmod(omp_get_wtime(), 10.0f));
    prs_rands  r;
    r.bypass(NN);
    printf("[%lf]array generated successfully\n", fmod(omp_get_wtime(), 10.0f));

    /* 时间记录相关变量 */
    double timeBegin = 0, timeCurrent = 0, timeRef[4] = { 0 };

    /* 测试1：遍历求最值 */
    printf("[%lf]test1:get max by origin way\n", fmod(omp_get_wtime(), 10.0f));
    timeBegin = omp_get_wtime();
    float_t max_origin = prs_max(r.seq, r.n);
    timeCurrent = omp_get_wtime();
    timeRef[0] = timeCurrent - timeBegin;

    /* 测试2：OMP加速求最值 */
    printf("[%lf]test2:speed up with openmp\n", fmod(omp_get_wtime(), 10.0f));
    timeBegin = omp_get_wtime();
    float_t max_omp = prs_max_omp(r.seq, r.n);
    timeCurrent = omp_get_wtime();
    timeRef[1] = timeCurrent - timeBegin;

    /* 测试3：OMP+AVX加速求最值 */
    printf("[%lf]test3:speed up with OMP and AVX.ISA\n", fmod(omp_get_wtime(), 10.0f));
    timeBegin = omp_get_wtime();
    float_t max_avx = prs_max_omp_avx(r.seq, r.n);
    timeCurrent = omp_get_wtime();
    timeRef[2] = timeCurrent - timeBegin;

    /* 测试4：TCP/IP加速 */
    printf("[%lf]test4:speed up with TCP/IP\n", fmod(omp_get_wtime(), 10.0f));
    float_t max_from_s = 0.0f, max_from_c = 0.0f;
    timeBegin = omp_get_wtime();
#pragma omp parallel
    {
#pragma omp sections 
        {
#pragma omp section
            {
                server.tx(&(r.seq[NN / 2]), NN / 2);
            }
#pragma omp section
            {
                max_from_s = prs_max(r.seq, NN / 2);
            }
        }

    }


    //printf("finish max=%f\n", max_from_s);
    server.rx(&max_from_c, 1);
    //printf("get client max=%f\n", max_from_c);
    float_t max_tcp = prs_max_merge(max_from_s, max_from_c);
    timeCurrent = omp_get_wtime();
    timeRef[3] = timeCurrent - timeBegin;

    /* 输出报告 */
    printf("\n______________MAX__SUMMARY________________\n");
    printf("|method\t|  value\t| time\t| ACR\t|\n");
    printf("------------------------------------------\n");
    printf("|orign\t|  %.4f\t|%.4lf\t|%.3lf\t|\n", max_origin, timeRef[0], timeRef[0] / timeRef[0]);
    printf("| omp\t|  %.4f\t|%.4lf\t|%.3lf\t|\n", max_omp, timeRef[1], timeRef[0] / timeRef[1]);
    printf("| avx\t|  %.4f\t|%.4lf\t|%.3lf\t|\n", max_avx, timeRef[2], timeRef[0] / timeRef[2]);
    printf("|TCPIP\t|  %.4f\t|%.4lf\t|%.3lf\t|\n", max_tcp, timeRef[3], timeRef[0] / timeRef[3]);
}

void qrs_performance_test_qsort()
{
    /* 建立TCP/IP服务器 */
    prs_tcp_server server;
    server.serverIp = "127.0.0.1";
    server.serverPort = 8081;
    /* 开始监听客户端 */
    server.begin();

    /* 建立随机变量 */
    printf("[%lf]begin to generate random array\n", fmod(omp_get_wtime(), 100.0f));
    prs_rands  r(NN);
    printf("[%lf]array generated successfully\n", fmod(omp_get_wtime(), 100.0f));

    /* 时间记录相关变量 */
    double timeBegin = 0, timeCurrent = 0, timeRef[3] = { 0 };

    /* 测试1：普通快速排序 */
    printf("[%lf]test1:qsort by origin way\n", fmod(omp_get_wtime(), 100.0f));
    timeBegin = omp_get_wtime();
    prs_qsort(r.seq, 0,r.n-1);
    timeCurrent = omp_get_wtime();
    timeRef[0] = timeCurrent - timeBegin;

    /* 建立随机变量 */
    printf("[%lf]begin to generate random array\n", fmod(omp_get_wtime(), 100.0f));
    r.generate(NN);
    printf("[%lf]array generated successfully\n", fmod(omp_get_wtime(), 100.0f));

    /* 测试2：OMP加速排序 */
    printf("[%lf]test2:speed up with openmp\n", fmod(omp_get_wtime(), 100.0f));
    timeBegin = omp_get_wtime();
    prs_qsort_omp(r.seq, 0, r.n - 1,16);
    timeCurrent = omp_get_wtime();
    timeRef[1] = timeCurrent - timeBegin;

    /* 建立随机变量 */
    printf("[%lf]begin to generate random array\n", fmod(omp_get_wtime(), 100.0f));
    r.generate(NN);
    printf("[%lf]array generated successfully\n", fmod(omp_get_wtime(), 100.0f));

    /* 测试3：TCP/IP双机加速排序 */
    printf("[%lf]test3:speed up with TCP/IP\n", fmod(omp_get_wtime(), 100.0f));
    timeBegin = omp_get_wtime();
#pragma omp parallel
    {
#pragma omp sections 
        {
#pragma omp section
            {
                server.tx(&(r.seq[NN / 2]), NN / 2);
            }
#pragma omp section
            {
                prs_qsort(r.seq, 0, r.n/2 - 1);
            }
        }

    }
    /* 接收已经排序的另外一半 */
    server.rx(&(r.seq[NN / 2]), NN / 2);
    /* 归并数据 */
    qrs_qsort_merge(r.seq, 0, NN / 2, NN - 1);
    timeCurrent = omp_get_wtime();
    timeRef[2] = timeCurrent - timeBegin;

    /* 输出报告 */
    printf("\n________QSORT__SUMMARY____________\n");
    printf("|method\t| time\t\t| ACR\t|\n");
    printf("------------------------------------\n");
    printf("|orign\t|%02.5lf\t|%.3lf\t|\n", timeRef[0], timeRef[0] / timeRef[0]);
    printf("| omp\t|%02.5lf\t|%.3lf\t|\n", timeRef[1], timeRef[0] / timeRef[1]);
    printf("|TCPIP\t|%02.5lf\t|%.3lf\t|\n", timeRef[2], timeRef[0] / timeRef[2]);
}

void client_func(int32_t func)
{
    float_t* seq = new float_t[NN / 2];
    double_t max_send = 0.0f, sum_send = 0.0f;
    prs_tcp_client client;
    client.clientIp = "127.0.0.1";
    client.clientPort = 8081;
    client.begin();

    switch (func)
    {
    case 1:
        /* 双机加速max */
        client.rx(seq, NN / 2);
        max_send = prs_max(seq, NN/2);
        client.tx(&max_send, 1);
        printf("finish max=%f\n",max_send);
        break;
    case 2:
        /* 双机加速sum */
        client.rx(seq, NN / 2);
        sum_send = prs_sum(seq, NN / 2);
        client.tx(&sum_send, 1);
        printf("finish sum=%lf\n", sum_send);
        break;
    case 3:
        /* 双机加速qsort */
        client.rx(seq, NN / 2);
        prs_qsort(seq, 0, NN / 2 - 1);
        client.tx(seq, NN / 2);
    default:
        break;
    }

    delete seq;
}